package com.huaxin.device.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.huaxin.device.dto.ResponseCode;
import com.huaxin.device.dto.ResponseResult;
import com.huaxin.device.dto.request.EquipmentCategoryCreateReqDTO;
import com.huaxin.device.dto.request.EquipmentCategoryPageListReqDTO;
import com.huaxin.device.dto.request.EquipmentCategoryUpdateReqDTO;
import com.huaxin.device.mapper.ElectricalEquipmentMapper;
import com.huaxin.device.mapper.EquipmentCategoryMapper;
import com.huaxin.device.mapper.EquipmentModelMapper;
import com.huaxin.device.mapping.EquipmentCategoryMapping;
import com.huaxin.device.models.EquipmentCategory;
import com.huaxin.device.service.EquipmentCategoryService;
import lombok.RequiredArgsConstructor;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;
import org.webjars.NotFoundException;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import static org.springframework.util.StringUtils.hasText;

@Service
@RequiredArgsConstructor
public class EquipmentCategoryServiceImpl extends ServiceImpl<EquipmentCategoryMapper, EquipmentCategory> implements EquipmentCategoryService {

    private final ApplicationContext applicationContext;
    private final EquipmentCategoryMapping mapping;
    private final EquipmentCategoryMapper mapper;
    private final ElectricalEquipmentMapper electricalEquipmentMapper;
    private final EquipmentModelMapper equipmentModelMapper;

    @Override
    public ResponseResult<EquipmentCategory> create(EquipmentCategoryCreateReqDTO in) {
        if (in == null) {
            return ResponseResult.parameterError(null, "参数不能为空");
        }

        // 校验 categoryCode + parentId + orgId 是否已存在
        if (existsByFields(EquipmentCategory::getCategoryCode, in.getCategoryCode(), in.getParentId(), in.getOrgId(), null)) {
            return ResponseResult.failure(ResponseCode.CUSTOM_BUSINESS_ERROR, "分类编码已存在", null);
        }
        // 校验 categoryName + parentId + orgId 是否已存在
        if (existsByFields(EquipmentCategory::getCategoryName, in.getCategoryName(), in.getParentId(), in.getOrgId(), null)) {
            return ResponseResult.failure(ResponseCode.CUSTOM_BUSINESS_ERROR, "分类名称已存在", null);
        }

        EquipmentCategory entity = mapping.toEntity(in);

        if (!save(entity)) {
            return ResponseResult.failure(ResponseCode.INTERNAL_SERVER_ERROR, "创建失败", null);
        }

        return ResponseResult.ok(getById(entity.getId()));
    }

    @Override
    public EquipmentCategory getByCategoryId(String id) {
        if (!hasText(id)) {
            throw new IllegalArgumentException("ID不能为空");
        }
        EquipmentCategory entity = getById(id);
        if (entity == null) {
            throw new NotFoundException("分类不存在");
        }
        return entity;
    }

    @Override
    public ResponseResult<String> update(EquipmentCategoryUpdateReqDTO in) {
        if (in == null) {
            return ResponseResult.parameterError(null, "参数不能为空");
        }

        EquipmentCategory entity = getByCategoryId(in.getId());

        // 校验 categoryCode + parentId + orgId 是否已存在（不包含当前ID）
        if (existsByFields(EquipmentCategory::getCategoryCode, in.getCategoryCode(), in.getParentId(), in.getOrgId(), entity.getId())) {
            return ResponseResult.failure(ResponseCode.CUSTOM_BUSINESS_ERROR, "分类编码已存在", null);
        }
        // 校验 categoryName + parentId + orgId 是否已存在（不包含当前ID）
        if (existsByFields(EquipmentCategory::getCategoryName, in.getCategoryName(), in.getParentId(), in.getOrgId(), entity.getId())) {
            return ResponseResult.failure(ResponseCode.CUSTOM_BUSINESS_ERROR, "分类名称已存在", null);
        }

        mapping.updateEntity(in, entity);
        if (!updateById(entity)) {
            return ResponseResult.failure(ResponseCode.INTERNAL_SERVER_ERROR, "更新失败", null);
        }

        return ResponseResult.ok("更新成功");
    }

    @Override
    public ResponseResult<String> delete(String id) {
        EquipmentCategory entity = getByCategoryId(id);

        if (this.hasChildren(id)) {
            return ResponseResult.failure(ResponseCode.CUSTOM_BUSINESS_ERROR, "请先删除子分类", null);
        }

        // 检查是否有设备关联该分类
        if (electricalEquipmentMapper.existsByCategoryId(id)) {
            return ResponseResult.failure(ResponseCode.CUSTOM_BUSINESS_ERROR, "请先删除关联的设备", null);
        }
        // 检查是否有型号关联该分类
        if (equipmentModelMapper.existsByCategoryId(id)) {
            return ResponseResult.failure(ResponseCode.CUSTOM_BUSINESS_ERROR, "请先删除关联的型号", null);
        }

        boolean removed = this.applicationContext.getBean(EquipmentCategoryService.class).removeById(id);
        if (!removed) {
            return ResponseResult.failure(ResponseCode.INTERNAL_SERVER_ERROR, "删除失败", null);
        }

        return ResponseResult.ok("删除成功");
    }

    @Override
    public ResponseResult<IPage<EquipmentCategory>> pageQuery(EquipmentCategoryPageListReqDTO in) {
        if (in == null) {
            return ResponseResult.parameterError(null, "参数错误");
        }

        IPage<EquipmentCategory> page = new Page<>(in.getPageNum(), in.getPageSize());
        LambdaQueryWrapper<EquipmentCategory> wrapper = new LambdaQueryWrapper<>();

        if (hasText(in.getCategoryCode())) {
            wrapper.eq(EquipmentCategory::getCategoryCode, in.getCategoryCode());
        }
        if (hasText(in.getParentId())) {
            wrapper.eq(EquipmentCategory::getParentId, in.getParentId());
        }
        if (in.getLevel() != null) {
            wrapper.eq(EquipmentCategory::getLevel, in.getLevel());
        }
        if (hasText(in.getOrgId())) {
            wrapper.like(EquipmentCategory::getOrgId, in.getOrgId());
        }
        if (hasText(in.getKeyword())) {
            wrapper.and(wrapper1 -> wrapper1
                    .like(EquipmentCategory::getCategoryName, in.getKeyword())
                    .or()
                    .like(EquipmentCategory::getDescription, in.getKeyword())
            );
        }

        wrapper.orderByDesc(EquipmentCategory::getSortOrder)
                .orderByAsc(EquipmentCategory::getCreatedAt);

        IPage<EquipmentCategory> result = page(page, wrapper);
        return ResponseResult.ok(result);
    }

    @Override
    public List<EquipmentCategory> getCategoryTree() {
        List<EquipmentCategory> all = list();
        return buildTree(all);
    }

    private List<EquipmentCategory> buildTree(List<EquipmentCategory> categories) {
        Map<String, EquipmentCategory> map = categories.stream()
                .collect(Collectors.toMap(EquipmentCategory::getId, e -> e));

        List<EquipmentCategory> root = new ArrayList<>();
        for (EquipmentCategory node : categories) {
            if (!hasText(node.getParentId())) {
                root.add(node);
            } else {
                EquipmentCategory parent = map.get(node.getParentId());
                if (parent != null && parent.getChildren() == null) {
                    parent.setChildren(new ArrayList<>());
                }
                if (parent != null) {
                    parent.getChildren().add(node);
                }
            }
        }
        return root;
    }

    /**
     * 检查分类是否存在子分类
     *
     * @param id 分类ID
     * @return 是否存在子分类
     */
    private boolean hasChildren(String id) {
        LambdaQueryWrapper<EquipmentCategory> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(EquipmentCategory::getParentId, id);
        return this.count(wrapper) > 0;
    }

    /**
     * 检查多个字段值组合是否在指定父级分类下已存在（排除当前ID）
     *
     * @param fieldGetter 字段Getter
     * @param fieldValue  字段值
     * @param parentId    父级分类ID
     * @param orgId       组织ID
     * @param excludeId   要排除的ID（可为null）
     * @return 是否存在匹配记录
     */
    private boolean existsByFields(
            SFunction<EquipmentCategory, ?> fieldGetter,
            Object fieldValue,
            String parentId,
            String orgId,
            String excludeId) {

        if (fieldGetter == null) return false;

        LambdaQueryWrapper<EquipmentCategory> wrapper = new LambdaQueryWrapper<>();

        if (fieldValue == null ||
                (fieldValue instanceof CharSequence cs && cs.toString().trim().isEmpty())) {
            wrapper.and(wrapper1 -> wrapper1
                    .isNull(fieldGetter)
                    .or().eq(fieldGetter, "")
            );
        } else {
            wrapper.eq(fieldGetter, fieldValue.toString().trim());
        }

        if (parentId == null || parentId.trim().isEmpty()) {
            wrapper.and(wrapper1 -> wrapper1
                    .isNull(EquipmentCategory::getParentId)
                    .or().eq(EquipmentCategory::getParentId, "")
            );
        } else {
            wrapper.eq(EquipmentCategory::getParentId, parentId.trim());
        }

        if (orgId == null || orgId.trim().isEmpty()) {
            wrapper.and(wrapper1 -> wrapper1
                    .isNull(EquipmentCategory::getOrgId)
                    .or().eq(EquipmentCategory::getOrgId, "")
            );
        } else {
            wrapper.eq(EquipmentCategory::getOrgId, orgId.trim());
        }

        if (excludeId != null && !excludeId.trim().isEmpty()) {
            wrapper.ne(EquipmentCategory::getId, excludeId.trim());
        }

        return this.count(wrapper) > 0;
    }
}